using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;

namespace CGF
{
    //Uinty可配合 CircleLayoutGroup 使用
    //传入的参数Transform是旋转对象
    public class PrizeWheel : MonoBehaviour
    {
        [Header("加速时长（秒）")]
        public float accelDuration = 1;
        [Header("减速圈数")]
        public int decelRounds = 6;
        [Header("减速时长（秒）")]
        public float decelDuration = 6;
        [Header("是否反转（默认顺时针）")]
        public bool reverse;
        [Header("闲置时是否支持转着玩")]
        public bool freeRotate = true;
        [Header("指针")]
        public Transform pointer;
        [Header("轮盘格子数量")]
        public float tableCount = 16;
        [Header("指针碰撞偏移角度")]
        public float hitAngleOffset = 0;
        [Header("指针碰撞音效")]
        public AudioClip pointerSound;

        public bool isRunning { get; private set; }
        private bool isDraging;
        private float previousAngle, dragDelta;
        private float setRunningFalseTimer;
        private bool canListenPointer;
        private float pointerHitAngle;
        private Camera uiCamera;
        private Tweener tweener;

        public void OnDestroy()
        {
            if (tweener != null)
            {
                tweener.Kill();
            }
        }

        void Awake()
        {
            if (transform as RectTransform)
            {
                CanvasScaler canvasScaler = transform.GetComponentInParent<CanvasScaler>();
                Canvas canvas = canvasScaler.GetComponent<Canvas>();
                if (canvas && canvas.renderMode != RenderMode.ScreenSpaceOverlay)
                {
                    uiCamera = canvas.worldCamera;
                }
            }

            CButton button = GetComponent<CButton>();
            if (button)
            {
                Image image = GetComponent<Image>();
                if (image)
                {
                    image.raycastTarget = true;
                }
                else
                {
                    RawImage rawImage = GetComponent<RawImage>();
                    if (rawImage) rawImage.raycastTarget = true;
                }
                button.triggerInterval = 0;
                button.globalSound = false;
                button.transition = CButton.Transition.None;
                button.SetPress(() =>
                {
                    if (freeRotate && transform is RectTransform && !this.isRunning)
                    {
                        if (!uiCamera)
                        {
                            Debug.LogError("Canvas使用UICamera才能自由旋转轮盘");
                            return;
                        }
                        Vector3 wheelCenter = transform.position;
                        Vector3 screenPos = new Vector3(Input.mousePosition.x, Input.mousePosition.y, transform.position.z);
                        Vector2 downPos = uiCamera.ScreenToWorldPoint(screenPos);
                        previousAngle = Mathf.Atan2(downPos.y - wheelCenter.y, downPos.x - wheelCenter.x) * Mathf.Rad2Deg;
                        isDraging = true;
                        dragDelta = 0;
                    }
                });
            }
        }

        public void Update()
        {
            if (freeRotate && !this.isRunning)
            {
                //自由转动
                if (isDraging)
                {
                    Vector3 wheelCenter = transform.position;
                    Vector3 screenPos = new Vector3(Input.mousePosition.x, Input.mousePosition.y, transform.position.z);
                    Vector2 downPos = uiCamera.ScreenToWorldPoint(screenPos);
                    float angle = Mathf.Atan2(downPos.y - wheelCenter.y, downPos.x - wheelCenter.x) * Mathf.Rad2Deg;
                    dragDelta = angle - previousAngle;
                    previousAngle = angle;
                    if (Input.GetMouseButtonUp(0))
                    {
                        isDraging = false;
                    }
                }
                else
                {
                    dragDelta += (0 - dragDelta) * 0.05f;
                }
                Vector3 wheelAngle = transform.localEulerAngles;
                wheelAngle.z += dragDelta;
                transform.localEulerAngles = wheelAngle;
            }

            if (setRunningFalseTimer > 0 && setRunningFalseTimer < Time.time)
            {
                setRunningFalseTimer = 0;
                isRunning = false;
            }

            //指针回弹
            if (pointer)
            {
                if (isRunning && canListenPointer)
                {
                    float incAngle = 360 / (float)tableCount;
                    float angleOffset = Angle360(transform.localEulerAngles.z) % incAngle;
                    float pointerTargetAngle = incAngle - angleOffset;
                    //钉子碰撞的角度区域
                    if (hitAngleOffset > pointerTargetAngle)
                    {
                        OnPonterHit();
                    }
                    hitAngleOffset = pointerTargetAngle;

                    if (pointerHitAngle < pointerTargetAngle) pointerHitAngle = pointerTargetAngle;

                    //指针摆动幅度系数
                    float pointerAngleRatio = 1.5f;
                    pointer.localEulerAngles = new Vector3(0, 0, pointerHitAngle * pointerAngleRatio);

                    //回弹
                    if (pointerHitAngle > 0)
                    {
                        pointerHitAngle -= 300 * Time.deltaTime;
                        if (pointerHitAngle < 0)
                        {
                            pointerHitAngle = 0;
                        }
                    }
                }
            }
        }

        private float Angle360(float angle)
        {
            while (angle < 0)
            {
                angle += 360;
            }
            while (angle > 360)
            {
                angle -= 360;
            }
            return angle;
        }

        #region 对外方法///////////////////////////////////////////////////////////////////////

        //初始化到原始角度
        public void InitAngle()
        {
            transform.localEulerAngles = Vector3.zero;
        }

        /// <summary>
        /// 开始旋转
        /// </summary>
        /// <param name="stopAngle">停止在规定的角度</param>
        public async CTask StartRun(float stopAngle)
        {
            if (isRunning)
            {
                return;
            }
            CTask rotateTask = CTask.Create();
            isDraging = false;
            dragDelta = 0;
            isRunning = true;
            canListenPointer = true;
            float _stopAngle = stopAngle - decelRounds * 360;
            if (reverse)
            {
                _stopAngle = stopAngle + decelRounds * 360;
            }
            //加速一圈
            float targetAngle = reverse ? transform.localEulerAngles.z + 360 : transform.localEulerAngles.z - 360;
            tweener = DOVirtual.Float(transform.localEulerAngles.z, targetAngle, accelDuration, (float z) =>
            {
                if (!isRunning || !gameObject) return;
                transform.localEulerAngles = new Vector3(0, 0, z);
            }).SetEase(Ease.InSine).OnComplete(() =>
            {
                if (!isRunning || !gameObject) return;
                //开始减速
                tweener = transform.DOLocalRotate(new Vector3(0, 0, _stopAngle), decelDuration, RotateMode.FastBeyond360)
                .OnComplete(() =>
                {
                    if (!gameObject) return;
                    setRunningFalseTimer = Time.time + 1f;
                    rotateTask.SetResult();
                    ModifyPointer();
                });
            });
            await rotateTask;
        }

        private async void ModifyPointer()
        {
            if (pointer)
            {
                await CTask.Wait(0.1f);
                canListenPointer = false;
                if (pointerHitAngle > 0)
                {
                    pointerHitAngle = 0;
                    pointer.localEulerAngles = new Vector3(0, 0, pointerHitAngle);
                    OnPonterHit();
                }
            }
        }

        private void OnPonterHit()
        {
            SoundPlayer.Play(pointerSound);
        }

        /// <summary>
        /// 直接停在指定角度
        /// </summary>
        public void StopAt(float angle)
        {
            isRunning = false;
            transform.DOKill();
            transform.localEulerAngles = new Vector3(0, 0, angle);
        }

        #endregion

    }
}